package org.tbwork.utility.httprr;

import java.net.InetAddress;
import java.util.Collection;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.protocol.HttpContext;

/** Provide common configurations of HTTP connection.<p>
 * @author Tommy.Tang
 * Date: 2014-09-10.
 */
public final class HttpConfig{

	 /**
	 * Sometimes, some website will detect your crawler by access rate. In case of this situation, this field is useful.
	 * This field is used to diminish the frequency of access when HTTPRR reads response successfully.<p>
	 * Of course, you can also use Sleep() function to implement it by yourself.<p>
	 * Unit: ms
	 */
	 private  long intervalTimeWhenSuccess = 0l;
 
	 /**
	 * Sometimes, some web-site will detect your crawler by access rate. In case of this situation, this field is useful.
	 * This field is used to diminish the frequency of access when HTTPRR failed to read response.<p>
	 * Of course, you can also use Sleep() function to implement it by yourself.<p>
	 * Usually, this value should be larger than intervalTimeWhenSuccess.
	 * <p>
	 * Unit: ms
	 */
	 private  long  intervalTimeWhenFail =0l;

	 /**
	 * In some cases, you may want to retry sending request.<br>
	 * You can set the count of retry times via this field.
	 */
	 private  int  retryTimeCount = 2;
	 
	 /**
	 * In some cases you may want HTTPRR can record the cookies set by the web-server, like:<p>
	 * (i) The web-site prevent itself from crawler robot by setting cookies which will be used in next request.<p>
	 * (ii) Some cookies in the response are necessary to build your next request.<p>
	 * true means HTTPRR will record cookies automatically, otherwise not.
	 */
	 private  boolean autoCookieRecord = false;
	 
	 /**
	 * Configurations from RequesetConfig.
	 */
	 private RequestConfig requestConfig = null;
	 
	 /*
	  * Proxy authentication
	  */
	 private boolean proxyAuthenEnabled = false;
	 private String proxyAuthenUsername = null; 
	 private String proxyAuthenPassowrd = null;
	 private HttpClientContext proxyAuthenContext = null;		 
	 
	 
	 /**
	 * Builder for HttpConfig used by HttpRR. 
	 */
	 public static class Builder
	 {
		 private  long intervalTimeWhenSuccess = 0l;
		 private  long  intervalTimeWhenFail =0l;
		 private  boolean autoCookieRecord = false; 
		 private  HttpHost proxy =null;
		 private boolean expectContinueEnabled; 
         private InetAddress localAddress;
         private boolean staleConnectionCheckEnabled;
         private String cookieSpec;
         private boolean redirectsEnabled;
         private boolean relativeRedirectsAllowed;
         private boolean circularRedirectsAllowed;
         private int maxRedirects;
         private boolean authenticationEnabled;
         private Collection<String> targetPreferredAuthSchemes;
         private Collection<String> proxyPreferredAuthSchemes;
         private int connectionRequestTimeout;
         private int connectTimeout;
         private int socketTimeout;
     	 private int retryTimeCount; 
     	 private boolean proxyAuthenEnabled = false;
    	 private String proxyAuthenUsername = null; 
    	 private String proxyAuthenPassowrd = null;
    	 private HttpClientContext proxyAuthenContext = null;		
		 /**
		 * Sometimes, some website will detect your crawler by access rate. In case of this situation, this field is useful.
		 * This field is used to diminish the frequency of access when HTTPRR reads response successfully.<p>
		 * Of course, you can also use Sleep() function to implement it by yourself.<p>
		 * Unit: ms
		 */
		 public Builder intervalTimeWhenSuccess(long intervalTimeWhenSuccess)
		 {
			 this.intervalTimeWhenSuccess =  intervalTimeWhenSuccess;
			 return this;
		 }
		 
         /**
     	 * In some cases, you may want to retry sending request.<br>
     	 * You can set the count of retry times via this field.
     	 */
		 public Builder retryTimeCount(int retryTimeCount)
		 {
			 this.retryTimeCount = retryTimeCount;
			 return this;
		 }
		 
		 /**
		 * Sometimes, some web-site will detect your crawler by access rate. In case of this situation, this field is useful.
		 * This field is used to diminish the frequency of access when HTTPRR failed to read response.<p>
		 * Of course, you can also use Sleep() function to implement it by yourself.<p>
		 * Usually, this value should be larger than intervalTimeWhenSuccess.
		 * <p>
		 * Unit: ms
		 */
		 public Builder intervalTimeWhenFail(long intervalTimeWhenFail)
		 {
			 this.intervalTimeWhenFail =  intervalTimeWhenFail;
			 return this;
		 }
		 
		 /**
		 * In some cases you may want HTTPRR can record the cookies set by the web-server, like:<p>
		 * (i) The web-site prevent itself from crawler robot by setting cookies which will be used in next request.<p>
		 * (ii) Some cookies in the response are necessary to build your next request.<p>
		 * true means HTTPRR will record cookies automatically, otherwise not.
		 */
		 public Builder autoCookieRecord(boolean autoCookieRecord)
		 {
			 this.autoCookieRecord =  autoCookieRecord;
			 return this;
		 }
		 
		 public Builder proxyUserName(String username){
			 this.proxyAuthenUsername = username;
			 return this;
		 }
		 
		 public Builder proxyPassword(String password){
			 this.proxyAuthenPassowrd = password;
			 return this;
		 }
		 
		 public Builder proxyAuthenEnabled(boolean enabled){
			 this.proxyAuthenEnabled = enabled;
			 return this;
		 }
		 
		 public Builder setExpectContinueEnabled(final boolean expectContinueEnabled) {
            this.expectContinueEnabled = expectContinueEnabled;
            return this;
         }

         public Builder setProxy(final HttpHost proxy) {
            this.proxy = proxy;
            return this;
         }

         public Builder setLocalAddress(final InetAddress localAddress) {
            this.localAddress = localAddress;
            return this;
         }

         public Builder setStaleConnectionCheckEnabled(final boolean staleConnectionCheckEnabled) {
            this.staleConnectionCheckEnabled = staleConnectionCheckEnabled;
            return this;
         }

         public Builder setCookieSpec(final String cookieSpec) {
            this.cookieSpec = cookieSpec;
            return this;
         }

         /**
     	 * When the http response is a forwarding response, you may want this.<p> 
     	 * true means HTTPRR will forward redirect requests automatically, otherwise not.
     	 */
         public Builder setRedirectsEnabled(final boolean redirectsEnabled) {
            this.redirectsEnabled = redirectsEnabled;
            return this;
         }

         public Builder setRelativeRedirectsAllowed(final boolean relativeRedirectsAllowed) {
            this.relativeRedirectsAllowed = relativeRedirectsAllowed;
            return this;
         }

         public Builder setCircularRedirectsAllowed(final boolean circularRedirectsAllowed) {
            this.circularRedirectsAllowed = circularRedirectsAllowed;
            return this;
         }

         public Builder setMaxRedirects(final int maxRedirects) {
            this.maxRedirects = maxRedirects;
            return this;
         }

         public Builder setAuthenticationEnabled(final boolean authenticationEnabled) {
            this.authenticationEnabled = authenticationEnabled;
            return this;
         }

         public Builder setTargetPreferredAuthSchemes(final Collection<String> targetPreferredAuthSchemes) {
            this.targetPreferredAuthSchemes = targetPreferredAuthSchemes;
            return this;
         }

         public Builder setProxyPreferredAuthSchemes(final Collection<String> proxyPreferredAuthSchemes) {
            this.proxyPreferredAuthSchemes = proxyPreferredAuthSchemes;
            return this;
         }

         public Builder setConnectionRequestTimeout(final int connectionRequestTimeout) {
            this.connectionRequestTimeout = connectionRequestTimeout;
            return this;
         }

         public Builder setConnectTimeout(final int connectTimeout) {
            this.connectTimeout = connectTimeout;
            return this;
         }

         public Builder setSocketTimeout(final int socketTimeout) {
            this.socketTimeout = socketTimeout;
            return this;
         } 
         
		 /**
		 * Given a default Builder instance with default HttpConfig values.
		 */
		 private Builder()
		 {
			 intervalTimeWhenSuccess = 0l;
			 intervalTimeWhenFail =0l; 
			 autoCookieRecord = false;
			 retryTimeCount = 1;
			 proxy = null;
		 } 
		 
		 /**
		 * @return the HttpConfig instance
		 */
		 public HttpConfig build()
		 {
			 HttpConfig httpConfig = new HttpConfig();
			 httpConfig.setAutoCookieRecord(this.autoCookieRecord);
			 httpConfig.setIntervalTimeWhenFail(this.intervalTimeWhenFail);
			 httpConfig.setIntervalTimeWhenSuccess(this.intervalTimeWhenFail);  
			 httpConfig.requestConfig =  RequestConfig.custom()
			 							.setAuthenticationEnabled(authenticationEnabled)
			 							.setCircularRedirectsAllowed(circularRedirectsAllowed)
			 							.setConnectionRequestTimeout(connectionRequestTimeout)
			 							.setConnectTimeout(connectTimeout)
			 							.setCookieSpec(cookieSpec)
			 							.setExpectContinueEnabled(expectContinueEnabled)
			 							.setLocalAddress(localAddress)
			 							.setMaxRedirects(maxRedirects)
			 							.setProxy(proxy)
			 							.setProxyPreferredAuthSchemes(proxyPreferredAuthSchemes)
			 							.setRedirectsEnabled(redirectsEnabled)
			 							.setRelativeRedirectsAllowed(relativeRedirectsAllowed)
			 							.setSocketTimeout(socketTimeout)
			 							.setStaleConnectionCheckEnabled(staleConnectionCheckEnabled)
			 							.setTargetPreferredAuthSchemes(targetPreferredAuthSchemes)
			 							.build(); 
			 if(httpConfig.isProxyAuthenEnabled())
				 httpConfig.setProxyAuthenContext(createProxyContext(this.proxyAuthenUsername, this.proxyAuthenPassowrd));
			 return httpConfig;
		 }
		 
		 private HttpClientContext createProxyContext(String username, String password){
			 CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
			 credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials( username +":"+ password));
			 HttpClientContext localContext = HttpClientContext.create();
			 localContext.setCredentialsProvider(credentialsProvider);
			 return localContext;
		 }
	 }
	 
	 
	 
	 private HttpConfig()
	 {
		 	super();
	 } 

	
     /** Use it to customize your Request configuration.
     * @return
     */
    public static HttpConfig.Builder custom() {
         return new Builder();
     }
	 
	/**
	 * Sometimes, some website will detect your crawler by access rate. In case of this situation, this field is useful.
	 * This field is used to diminish the frequency of access when HTTPRR reads response successfully.<p>
	 * Of course, you can also use Sleep function to implement this by yourself.<p>
	 * Unit: ms
	 */
	public long getIntervalTimeWhenSuccess() {
		return intervalTimeWhenSuccess;
	}


	/**
	 * Sometimes, some web-site will detect your crawler by access rate. In case of this situation, this field is useful.
	 * This field is used to diminish the frequency of access when HTTPRR failed to read response.<p>
	 * Of course, you can also use Sleep function to implement this by yourself.<p>
	 * Usually, this value should be larger than intervalTimeWhenSuccess.
	 * <p>
	 * Unit: ms
	 */
	public long getIntervalTimeWhenFail() {
		return intervalTimeWhenFail;
	}

	/**
	 * In some cases you may want HTTPRR can record the cookies set by the web-server, like:<p>
	 * (i) The web-site prevent itself from crawler robot by setting cookies which will be used in next request.<p>
	 * (ii) Some cookies in the response are necessary to build your next request.<p>
	 * true means HTTPRR will record cookies automatically, otherwise not.
	 */
	public boolean isAutoCookieRecord() {
		return autoCookieRecord;
	}

	/**
	 * Sometimes, some website will detect your crawler by access rate. In case of this situation, this field is useful.
	 * This field is used to diminish the frequency of access when HTTPRR reads response successfully.<p>
	 * Of course, you can also use Sleep function to implement this by yourself.<p>
	 * Unit: ms
	 */
	public void setIntervalTimeWhenSuccess(long intervalTimeWhenSuccess) {
		this.intervalTimeWhenSuccess = intervalTimeWhenSuccess;
	}
	
	/**
	 * Sometimes, some web-site will detect your crawler by access rate. In case of this situation, this field is useful.
	 * This field is used to diminish the frequency of access when HTTPRR failed to read response.<p>
	 * Of course, you can also use Sleep function to implement this by yourself.<p>
	 * Usually, this value should be larger than intervalTimeWhenSuccess.
	 * <p>
	 * Unit: ms
	 */
	public void setIntervalTimeWhenFail(long intervalTimeWhenFail) {
		this.intervalTimeWhenFail = intervalTimeWhenFail;
	}

	/**
	 * In some cases you may want HTTPRR can record the cookies set by the web-server, like:<p>
	 * (i) The web-site prevent itself from crawler robot by setting cookies which will be used in next request.<p>
	 * (ii) Some cookies in the response are necessary to build your next request.<p>
	 * true means HTTPRR will record cookies automatically, otherwise not.
	 */
	public void setAutoCookieRecord(boolean autoCookieRecord) {
		this.autoCookieRecord = autoCookieRecord;
	}
 

	public RequestConfig getRequestConfig() {
		return requestConfig;
	}

	public void setRequestConfig(RequestConfig requestConfig) {
		this.requestConfig = requestConfig;
	}

    /**
	 * In some cases, you may want to retry sending request.<br>
	 * You can set the count of retry times via this field.
	 */
	public int getRetryTimeCount() {
		return retryTimeCount;
	}

    /**
	 * In some cases, you may want to retry sending request.<br>
	 * You can set the count of retry times via this field.
	 */
	public void setRetryTimeCount(int retryTimeCount) {
		this.retryTimeCount = retryTimeCount;
	}


	public boolean isProxyAuthenEnabled() {
		return proxyAuthenEnabled;
	}


	public void setProxyAuthenEnabled(boolean proxyAuthenEnabled) {
		this.proxyAuthenEnabled = proxyAuthenEnabled;
	}


	public String getProxyAuthenUsername() {
		return proxyAuthenUsername;
	}


	public void setProxyAuthenUsername(String proxyAuthenUsername) {
		this.proxyAuthenUsername = proxyAuthenUsername;
	}


	public String getProxyAuthenPassowrd() {
		return proxyAuthenPassowrd;
	}


	public void setProxyAuthenPassowrd(String proxyAuthenPassowrd) {
		this.proxyAuthenPassowrd = proxyAuthenPassowrd;
	}


	public HttpClientContext getProxyAuthenContext() {
		return proxyAuthenContext;
	}


	public void setProxyAuthenContext(HttpClientContext proxyAuthenContext) {
		this.proxyAuthenContext = proxyAuthenContext;
	}
 
}
